package com.kexio.dynamic.datasource.service.impl;

import com.kexio.dynamic.datasource.service.DynamicDataSourceService;
import com.zaxxer.hikari.HikariDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 动态数据源管理服务默认实现
 * 
 * @author Kexio
 * @since 1.0.0
 */
@Service
public class DefaultDynamicDataSourceService implements DynamicDataSourceService {

    private static final Logger log = LoggerFactory.getLogger(DefaultDynamicDataSourceService.class);

    // 数据源存储
    private final Map<String, DataSource> dataSources = new ConcurrentHashMap<>();
    
    // 数据源配置信息存储
    private final Map<String, DataSourceInfo> dataSourceInfos = new ConcurrentHashMap<>();
    
    // 数据源统计信息存储
    private final Map<String, DataSourceStats> dataSourceStats = new ConcurrentHashMap<>();
    
    // 数据源权重存储（用于负载均衡）
    private final Map<String, Integer> dataSourceWeights = new ConcurrentHashMap<>();
    
    // 数据源启用状态
    private final Map<String, Boolean> dataSourceEnabled = new ConcurrentHashMap<>();
    
    // 线程本地当前数据源
    private static final ThreadLocal<String> currentDataSource = new ThreadLocal<>();
    
    private static final String DEFAULT_DS = "master";

    @Override
    public void addDataSource(String dsName, DataSource dataSource) {
        if (dsName == null || dataSource == null) {
            throw new IllegalArgumentException("数据源名称和数据源实例不能为空");
        }
        
        dataSources.put(dsName, dataSource);
        dataSourceEnabled.put(dsName, true);
        dataSourceWeights.put(dsName, 1);
        
        // 初始化统计信息
        DataSourceStats stats = new DataSourceStats();
        stats.setName(dsName);
        stats.setWeight(1);
        dataSourceStats.put(dsName, stats);
        
        // 初始化数据源信息
        DataSourceInfo info = createDataSourceInfo(dsName, dataSource);
        dataSourceInfos.put(dsName, info);
        
        log.info("数据源已添加: {}", dsName);
    }

    @Override
    public void addDataSource(String dsName, DataSourceProperty property) {
        if (dsName == null || property == null) {
            throw new IllegalArgumentException("数据源名称和配置属性不能为空");
        }
        
        try {
            DataSource dataSource = createDataSource(property);
            addDataSource(dsName, dataSource);
        } catch (Exception e) {
            log.error("创建数据源失败: {}", dsName, e);
            throw new RuntimeException("创建数据源失败: " + dsName, e);
        }
    }

    @Override
    public boolean removeDataSource(String dsName) {
        if (dsName == null || DEFAULT_DS.equals(dsName)) {
            log.warn("不能移除默认数据源: {}", dsName);
            return false;
        }
        
        DataSource dataSource = dataSources.remove(dsName);
        if (dataSource != null) {
            try {
                // 关闭数据源
                if (dataSource instanceof HikariDataSource) {
                    ((HikariDataSource) dataSource).close();
                }
                
                // 清理相关信息
                dataSourceInfos.remove(dsName);
                dataSourceStats.remove(dsName);
                dataSourceWeights.remove(dsName);
                dataSourceEnabled.remove(dsName);
                
                log.info("数据源已移除: {}", dsName);
                return true;
            } catch (Exception e) {
                log.error("关闭数据源失败: {}", dsName, e);
            }
        }
        
        return false;
    }

    @Override
    public Set<String> getCurrentDataSources() {
        return dataSources.keySet();
    }

    @Override
    public DataSource getDataSource(String dsName) {
        return dataSources.get(dsName);
    }

    @Override
    public boolean exists(String dsName) {
        return dataSources.containsKey(dsName);
    }

    @Override
    public void switchToDataSource(String dsName) {
        if (exists(dsName) && isEnabled(dsName)) {
            currentDataSource.set(dsName);
            updateStats(dsName);
        } else {
            log.warn("数据源不存在或已禁用: {}", dsName);
        }
    }

    @Override
    public String getCurrentDataSource() {
        String ds = currentDataSource.get();
        return ds != null ? ds : DEFAULT_DS;
    }

    @Override
    public boolean testConnection(String dsName) {
        DataSource dataSource = getDataSource(dsName);
        if (dataSource == null) {
            return false;
        }
        
        try (Connection connection = dataSource.getConnection()) {
            return connection != null && !connection.isClosed();
        } catch (SQLException e) {
            log.warn("测试数据源连接失败: {}", dsName, e);
            return false;
        }
    }

    @Override
    public DataSourceInfo getDataSourceInfo(String dsName) {
        return dataSourceInfos.get(dsName);
    }

    @Override
    public void refreshDataSource(String dsName) {
        DataSourceInfo info = dataSourceInfos.get(dsName);
        if (info != null) {
            info.setLastActiveTime(System.currentTimeMillis());
            log.debug("数据源信息已刷新: {}", dsName);
        }
    }

    @Override
    public void refreshAllDataSources() {
        dataSourceInfos.values().forEach(info -> 
            info.setLastActiveTime(System.currentTimeMillis()));
        log.info("所有数据源信息已刷新");
    }

    @Override
    public void closeDataSource(String dsName) {
        if (DEFAULT_DS.equals(dsName)) {
            log.warn("不能关闭默认数据源: {}", dsName);
            return;
        }
        
        DataSource dataSource = dataSources.get(dsName);
        if (dataSource instanceof HikariDataSource) {
            try {
                ((HikariDataSource) dataSource).close();
                log.info("数据源已关闭: {}", dsName);
            } catch (Exception e) {
                log.error("关闭数据源失败: {}", dsName, e);
            }
        }
    }

    @Override
    public void closeAllDataSources() {
        dataSources.forEach((name, dataSource) -> {
            if (!DEFAULT_DS.equals(name) && dataSource instanceof HikariDataSource) {
                try {
                    ((HikariDataSource) dataSource).close();
                } catch (Exception e) {
                    log.error("关闭数据源失败: {}", name, e);
                }
            }
        });
        log.info("所有非默认数据源已关闭");
    }

    @Override
    public Map<String, DataSourceStats> getDataSourceStats() {
        return new ConcurrentHashMap<>(dataSourceStats);
    }

    @Override
    public void setDataSourceWeight(String dsName, int weight) {
        if (exists(dsName)) {
            dataSourceWeights.put(dsName, weight);
            DataSourceStats stats = dataSourceStats.get(dsName);
            if (stats != null) {
                stats.setWeight(weight);
            }
            log.debug("数据源权重已设置: {} = {}", dsName, weight);
        }
    }

    @Override
    public void toggleDataSource(String dsName, boolean enabled) {
        if (exists(dsName)) {
            dataSourceEnabled.put(dsName, enabled);
            DataSourceInfo info = dataSourceInfos.get(dsName);
            if (info != null) {
                info.setEnabled(enabled);
            }
            log.info("数据源状态已更新: {} = {}", dsName, enabled ? "启用" : "禁用");
        }
    }

    @Override
    public void addDataSources(Map<String, DataSource> dataSources) {
        if (dataSources != null) {
            dataSources.forEach(this::addDataSource);
            log.info("批量添加数据源完成，数量: {}", dataSources.size());
        }
    }

    /**
     * 检查数据源是否启用
     */
    private boolean isEnabled(String dsName) {
        return dataSourceEnabled.getOrDefault(dsName, true);
    }

    /**
     * 更新数据源统计信息
     */
    private void updateStats(String dsName) {
        DataSourceStats stats = dataSourceStats.get(dsName);
        if (stats != null) {
            stats.setTotalConnections(stats.getTotalConnections() + 1);
            stats.setLastUsedTime(System.currentTimeMillis());
        }
    }

    /**
     * 创建数据源
     */
    private DataSource createDataSource(DataSourceProperty property) {
        HikariDataSource dataSource = new HikariDataSource();
        
        dataSource.setJdbcUrl(property.getUrl());
        dataSource.setUsername(property.getUsername());
        dataSource.setPassword(property.getPassword());
        dataSource.setDriverClassName(property.getDriverClassName());
        
        // 连接池配置
        if (property.getInitialSize() != null) {
            dataSource.setMinimumIdle(property.getInitialSize());
        }
        if (property.getMaxActive() != null) {
            dataSource.setMaximumPoolSize(property.getMaxActive());
        }
        if (property.getMaxWait() != null) {
            dataSource.setConnectionTimeout(property.getMaxWait());
        }
        if (property.getValidationQuery() != null) {
            dataSource.setConnectionTestQuery(property.getValidationQuery());
        }
        
        // 其他属性
        if (property.getProperties() != null) {
            property.getProperties().forEach((key, value) -> 
                dataSource.addDataSourceProperty(key, value));
        }
        
        return dataSource;
    }

    /**
     * 创建数据源信息
     */
    private DataSourceInfo createDataSourceInfo(String dsName, DataSource dataSource) {
        DataSourceInfo info = new DataSourceInfo();
        info.setName(dsName);
        info.setEnabled(true);
        info.setCreateTime(System.currentTimeMillis());
        info.setLastActiveTime(System.currentTimeMillis());
        
        if (dataSource instanceof HikariDataSource) {
            HikariDataSource hikariDS = (HikariDataSource) dataSource;
            info.setUrl(hikariDS.getJdbcUrl());
            info.setDriverClassName(hikariDS.getDriverClassName());
            info.setMaxConnections(hikariDS.getMaximumPoolSize());
            info.setActiveConnections(hikariDS.getHikariPoolMXBean().getActiveConnections());
            info.setIdleConnections(hikariDS.getHikariPoolMXBean().getIdleConnections());
        }
        
        return info;
    }
}
